package com.example.kuaizu.service.imp;

import cn.hutool.core.collection.CollUtil;
import com.example.kuaizu.em.ProjectDelectStatus;
import com.example.kuaizu.email.EmailPromotion;
import com.example.kuaizu.mapper.EmailPromotionMapper;
import com.example.kuaizu.mapper.ProjectMapper;
import com.example.kuaizu.pojo.EmailPromotionParm;
import com.example.kuaizu.pojo.PageBean;
import com.example.kuaizu.pojo.PromotionInfoIdsParam;
import com.example.kuaizu.pojo.dto.UserEmailDao;
import com.example.kuaizu.pojo.ov.HouProjectOv;
import com.example.kuaizu.pojo.ov.PromotionArrayObjectOv;
import com.example.kuaizu.pojo.pram.PromotionMajorPram;
import com.example.kuaizu.pojo.pram.PromotionSchoolPram;
import com.example.kuaizu.service.InEmailPromotionService;
import com.example.kuaizu.utils.EmailPromotionUtils;
import com.example.kuaizu.utils.SerializerUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import kuaizu.common.exception.MassageException;
import kuaizu.common.param.PromotionInfoParam;
import kuaizu.common.tablepojo.Project;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.mail.Authenticator;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import static kuaizu.common.constp.KuaiZuConst.ERROR;

@Service
@Log4j2
public class EmailPromotionService implements InEmailPromotionService {
    @Autowired
    @Qualifier("emailProPerties")
    private Properties props;
    @Autowired
    private Authenticator authenticator;
    @Autowired
    private String USER_NAME;
    //线程池
    @Autowired
    private ThreadPoolTaskExecutor customThreadPool;
    @Autowired
    private EmailPromotionMapper emailPromotionMapper;
    @Autowired
    private ApplicationContext applicationContext;

    //邮件模版
    @Autowired
    EmailPromotion emailPromotionBean;

    @Autowired
    private ProjectMapper projectMapper;

    //邮件推广
    @Transactional
    @Override
    public void sendEmail(PromotionArrayObjectOv promotionArrayObjectsOv) {
        //将数字id转成字符串
        String projectId = promotionArrayObjectsOv.getProjectId().toString();
        //根据项目id查询项目的信息
        Project project = projectMapper.selectProjectById(projectId);
        if (project == null) {
            log.error("项目不存在");
            throw new MassageException(ERROR, "项目不存在");
        }
        //设置项目的推广状态为正在推广中
        projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTIONING);
        //根据对应的学校和专业查询对应的邮箱地址,电话等信息,昵称等信息
        List<UserEmailDao> userEmail = emailPromotionMapper.selectEmailBySchoolAndMajor(promotionArrayObjectsOv.getPromotionArrayObject());
        if (CollUtil.isEmpty(userEmail)) {
            log.error("没有查询到对应的邮箱地址");
            throw new MassageException(ERROR, "没有查询到对应的邮箱地址");
        }
        if (userEmail.isEmpty()) {
            log.info("没有查询到对应的邮箱地址");
            projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTIONFAILED);
            throw new MassageException(ERROR, "没有查询到对应的邮箱地址");
        }
        customThreadPool.execute(() -> {
            //开启多线程
            boolean isSuccess = false;
            try {
                applicationContext.getBean(EmailPromotionService.class).sedEmail(promotionArrayObjectsOv, userEmail, project);
                isSuccess = true;
            } catch (Exception e) {
                log.error("发送邮件失败");
                throw new RuntimeException(e);
            } finally {
                //更新数据状态
                if (isSuccess) {
                    projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTION);
                } else {
                    projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTIONFAILED);
                }
            }
        });
        //log.info("查询到的邮箱地址为:" + strings);
        //将邮箱地址转换为数组
        //String[] emailAdds = strings.toArray(new String[strings.size()]);


    }

    //根据专业查看可能感兴趣的项目
    @Override
    @Transactional
    public Set<UserEmailDao> majorbyproject(Integer id) {
        return Set.of();
    }

    //查看推广详情
    @Override
    @Transactional
    public PageBean<HouProjectOv> getPromotionInfo(PromotionInfoParam req) {

        //创建pageBean对象
        PageBean<HouProjectOv> pd = new PageBean<>();
        //开启分夜茶叙 使用分页查询插件 导入坐标  当前页码 ,每页的数据
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        //调用mapper查询
        List<HouProjectOv> as = emailPromotionMapper.getPromotionInfo(req);
        //page中提供了方法可以获取pageHelper分页查询的结果 总数据条数,和当前页数据不强转看不到
        Page<HouProjectOv> p = (Page<HouProjectOv>) as;
        //把数据填充到pagebean中去
        pd.setItems(p.getResult());//获取指定页的数据
        pd.setTotal(p.getTotal());//获取总条数
        return pd;
    }

    //根据id列表查询项目
    @Override
    @Transactional
    public PageBean<HouProjectOv> getPromotionInfoByIds(PromotionInfoIdsParam req) {
        //判断id数组是否为空
        if (req.getIds().length == 0) {
            log.error("id数组不能为空");
            throw new MassageException(ERROR, "id数组不能为空");
        }
        //创建pageBean对象
        PageBean<HouProjectOv> pd = new PageBean<>();
        //开启分夜茶叙 使用分页查询插件 导入坐标  当前页码 ,每页的数据
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        //调用mapper查询
        List<HouProjectOv> as = emailPromotionMapper.getPromotionIdsInfo(req);
        //page中提供了方法可以获取pageHelper分页查询的结果 总数据条数,和当前页数据不强转看不到
        Page<HouProjectOv> p = (Page<HouProjectOv>) as;
        //把数据填充到pagebean中去
        pd.setItems(p.getResult());//获取指定页的数据
        pd.setTotal(p.getTotal());//获取总条数
        return pd;
    }

    @Override
    @Transactional
    public void sendEmailBySchoolList(PromotionSchoolPram pram) {
        //查询项目信息
        String projectId = pram.getProjectId().toString();
        Project project = projectMapper.selectProjectById(projectId);
        if (ObjectUtils.isEmpty(project)) {
            log.error("项目不存在");
            throw new MassageException(ERROR, "项目不存在");
        }
        //获取指定学校的用户信息
        List<UserEmailDao> userEmail = emailPromotionMapper.selectEmailBySchool(pram.getSchoolList());
        if (CollUtil.isEmpty(userEmail)) {
            log.error("没有查询到对应学校的用户信息");
            throw new MassageException(ERROR, "没有查询到对应学校的用户信息");
        }
        //设置项目的推广状态为正在推广中
        projectMapper.updateEmailPromotionStatus(pram.getProjectId().toString(), ProjectDelectStatus.PROMOTIONING);
        customThreadPool.execute(() -> {
            //开启多线程
            PromotionArrayObjectOv promotionArrayObjectOv = new PromotionArrayObjectOv();
            BeanUtils.copyProperties(pram, promotionArrayObjectOv);
            boolean isSuccess = false;
            try {
                applicationContext.getBean(EmailPromotionService.class).sedEmail(promotionArrayObjectOv, userEmail, project);
                isSuccess = true;
            } catch (Exception e) {
                log.error("发送邮件失败");
                throw new RuntimeException(e);
            } finally {
                //更新数据状态
                if (isSuccess) {
                    projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTION);
                } else {
                    projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTIONFAILED);
                }
            }
        });
    }

    @Override
    @Transactional
    public void sendEmailByMajorList(PromotionMajorPram pram) {
        //查询项目信息
        String projectId = pram.getProjectId().toString();
        Project project = projectMapper.selectProjectById(projectId);
        if (ObjectUtils.isEmpty(project)) {
            log.error("项目不存在");
            throw new MassageException(ERROR, "项目不存在");
        }
        //获取指定学校的用户信息
        List<UserEmailDao> userEmail = emailPromotionMapper.selectEmailByMajor(pram.getMajorlList());
        if (CollUtil.isEmpty(userEmail)) {
            log.error("没有查询到对应学校的用户信息");
            throw new MassageException(ERROR, "没有查询到对应学校的用户信息");
        }
        //设置项目的推广状态为正在推广中
        projectMapper.updateEmailPromotionStatus(pram.getProjectId().toString(), ProjectDelectStatus.PROMOTIONING);
        customThreadPool.execute(() -> {
            //开启多线程
            PromotionArrayObjectOv promotionArrayObjectOv = new PromotionArrayObjectOv();
            BeanUtils.copyProperties(pram, promotionArrayObjectOv);
            boolean isSuccess = false;
            try {
                applicationContext.getBean(EmailPromotionService.class).sedEmail(promotionArrayObjectOv, userEmail, project);
                isSuccess = true;
            } catch (Exception e) {
                log.error("发送邮件失败");
                throw new RuntimeException(e);
            } finally {
                //更新数据状态
                if (isSuccess) {
                    projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTION);
                } else {
                    projectMapper.updateEmailPromotionStatus(projectId, ProjectDelectStatus.PROMOTIONFAILED);
                }
            }
        });
    }

    /**
     * @param promotionArrayObjectsOv 推广的具体信息
     * @param userEmail               推广用户的邮件集合
     * @param project                 推广项目信息
     */
    @Async
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void sedEmail(PromotionArrayObjectOv promotionArrayObjectsOv, List<UserEmailDao> userEmail, Project project) {
        String projectId = promotionArrayObjectsOv.getProjectId().toString();
        //将promotionArrayObjectsOv序列化之后存到数据库中
        Integer tuiId = 0;
        EmailPromotionParm emailPromotion = new EmailPromotionParm();
        emailPromotion.setOpenid(promotionArrayObjectsOv.getOpenid());
        emailPromotion.setProjectId(projectId);
        try {
            String bytes = SerializerUtils.serializeToBase64(promotionArrayObjectsOv);
            //插入数据设置对应的状态为未推广
            emailPromotion.setEmailadds(bytes);
            emailPromotion.setPromotionStatus(ProjectDelectStatus.NOT_PROMOTION);
            emailPromotionMapper.insertPromotionArrayObjectOv(emailPromotion);
        } catch (IOException e) {
            log.error("保存数据失败");
            throw new RuntimeException(e);
        }
        //统计成功和失败的个数
        int successCount = 0;
        //遍历集合
        for (UserEmailDao ue : userEmail) {
            //发送邮件
            //设置对应的邮件内容
            Integer star = EmailPromotionUtils.sendEmail(new String[]{ue.getEmail()}, props, authenticator, USER_NAME, emailPromotionBean.sendEmailText(ue.getNickname(), project));
            if (star != null && star != 1) {
                successCount++;
            }
        }
        log.info("失败的个数:" + successCount);
        log.info("成功的个数:" + (userEmail.size() - successCount));
        //修改数据库中的状态为已推广
        emailPromotionMapper.updatePromotionStatus(promotionArrayObjectsOv.getOpenid(), projectId, ProjectDelectStatus.PROMOTION);
        //将推广完成的数据保存到数据库中
        //1.将数据序列化
        String info = "推广完成的个数:" + (userEmail.size() - successCount) + "推广失败的个数:" + successCount;
        String bytes = "等待序列化";
        try {
            bytes = SerializerUtils.serializeToBase64(promotionArrayObjectsOv);
        } catch (IOException e) {
            log.error("数据序列化失败");
            info += "数据序列化失败";
            throw new RuntimeException(e);
        } finally {
            log.info("插入数据的id为:" + tuiId);
            if (emailPromotion.getId() == null) {
                log.error("插入数据失败");
                log.error("序列化的内容:{}", bytes);
                log.error("提示信息:{}", info);
            }
            emailPromotionMapper.insertPromotionData(emailPromotion.getId(), bytes, info);
        }
    }
}

